// *********************************************
// * Raamatukogu  *
// *********************************************
// cl_camera.lua - Loads camera functionality


module( "camera", package.seeall )

local NaturalCamPos, ActualCamPos
local NaturalCamAng, ActualCamAng
local FOV
local CamParent, CamParentOrig

local SrcCamPos, SrcCamAng
local DstCamPos, DstCamAng
local FadeActive, EndFade, FadeTime

local function mid( a, b, d )
	return (b-a)*d + a
end

local function mid_sine( a, b, d )
	local newD = (1+math.sin( math.rad( (d*180)-90 ) ))*0.5
	return mid( a, b, newD )
end

function SetPos( pos )
	ActualCamPos = pos
end

function SetAng( ang )
	ActualCamAng = ang
end

local trace = {}
function GetTrace( dist )
	local ply = LocalPlayer()
	local fov = FOV or ply:GetFOV()
	local ang = ActualCamAng or NaturalCamAng
	local pos = ActualCamPos or NaturalCamPos
	local dir = gui.ScreenToVector( gui.MousePos() )
	trace.start = pos
	trace.endpos = trace.start + (dir*(dist or 2048))
	trace.filter = ply
	//print( dir:Dot( ang:Forward() ) )
	return util.TraceLine( trace )
end

function Reset()
	ActualCamPos = nil
	ActualCamAng = nil
	TargetCamPos = nil
	TargetCamAng = nil
end

function GetNaturalCamPos()
	return NaturalCamPos, NaturalCamAng
end

function SetFOV( v )
	FOV = v
end

function ResetFOV()
	FOV = nil
end

function FadeBetween( posa, anga, posb, angb, time )
	FadeActive = true
	FadeTime = time
	EndFade = CurTime() + time
	SrcCamPos = posa
	SrcCamAng = anga
	DstCamPos = posb
	DstCamAng = angb
end

local function CalcFadeState()
	if (!FadeActive) then return end
	local d = 1-math.Clamp( (EndFade - CurTime())/FadeTime, 0, 1 )
	if (d == 1) then
		FadeActive = false
		ActualCamPos = DstCamPos
		ActualCamAng = DstCamAng
	end
	local pos = mid_sine( SrcCamPos, DstCamPos, d )
	local ang = mid_sine( SrcCamAng:Forward(), DstCamAng:Forward(), d ):Angle()
	return pos, ang
end

local view = {}
function GM:CalcView( ply, origin, angles, fov )
	if (ply.ActiveStory && ply.ActiveStory.FirstPerson) then return end
	NaturalCamPos = origin
	NaturalCamAng = angles
	view.origin = origin
	view.angles = angles
	view.fov = fov
	if (FOV) then view.fov = FOV end
	if (ActualCamPos) then view.origin = ActualCamPos end
	if (ActualCamAng) then view.angles = ActualCamAng end
	if (ValidEntity( CamParent )) then
		view.origin = view.origin + (CamParent:GetPos() - CamParentOrig)
	end
	if (FadeActive) then
		local pos, ang = CalcFadeState()
		view.origin = pos
		view.angles = ang
	end
	return view
end

local function umCameraState( um )
	SetPos( um:ReadVector() )
	SetAng( um:ReadAngle() )
	local parent = um:ReadEntity()
	if (ValidEntity( parent )) then
		CamParent = parent
		CamParentOrig = parent:GetPos()
	else
		CamParent = nil
	end
end
usermessage.Hook( "_camerastate", umCameraState )

local function umCameraFade( um )
	local pos1, ang1 = um:ReadVector(), um:ReadAngle()
	local pos2, ang2 = um:ReadVector(), um:ReadAngle()
	local time = um:ReadFloat()
	FadeBetween( pos1, ang1, pos2, ang2, time )
end
usermessage.Hook( "_camerafade", umCameraFade )